#include "../server.hpp"
#include <sys/stat.h>
#include<regex>
#include<sstream>
#include<fstream>

        std::unordered_map<std::string,std::string> mimes = {
            {".aac",        "audio/aac"},
            {".abw",        "application/x-abiword"},
            {".arc",        "application/x-freearc"},
            {".avi",        "video/x-msvideo"},
            {".azw",        "application/vnd.amazon.ebook"},
            {".bin",        "application/octet-stream"},
            {".bmp",        "image/bmp"},
            {".bz",         "application/x-bzip"},
            {".bz2",        "application/x-bzip2"},
            {".csh",        "application/x-csh"},
            {".css",        "text/css"},
            {".csv",        "text/csv"},
            {".doc",        "application/msword"},
            {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {".eot",        "application/vnd.ms-fontobject"},
            {".epub",       "application/epub+zip"},
            {".gif",        "image/gif"},
            {".htm",        "text/html"},
            {".html",       "text/html"},
            {".ico",        "image/vnd.microsoft.icon"},
            {".ics",        "text/calendar"},
            {".jar",        "application/java-archive"},
            {".jpeg",       "image/jpeg"},
            {".jpg",        "image/jpeg"},
            {".js",         "text/javascript"},
            {".json",       "application/json"},
            {".jsonld",     "application/ld+json"},
            {".mid",        "audio/midi"},
            {".midi",       "audio/x-midi"},
            {".mjs",        "text/javascript"},
            {".mp3",        "audio/mpeg"},
            {".mpeg",       "video/mpeg"},
            {".mpkg",       "application/vnd.apple.installer+xml"},
            {".odp",        "application/vnd.oasis.opendocument.presentation"},
            {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
            {".odt",        "application/vnd.oasis.opendocument.text"},
            {".oga",        "audio/ogg"},
            {".ogv",        "video/ogg"},
            {".ogx",        "application/ogg"},
            {".otf",        "font/otf"},
            {".png",        "image/png"},
            {".pdf",        "application/pdf"},
            {".ppt",        "application/vnd.ms-powerpoint"},
            {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {".rar",        "application/x-rar-compressed"},
            {".rtf",        "application/rtf"},
            {".sh",         "application/x-sh"},
            {".svg",        "image/svg+xml"},
            {".swf",        "application/x-shockwave-flash"},
            {".tar",        "application/x-tar"},
            {".tif",        "image/tiff"},
            {".tiff",       "image/tiff"},
            {".ttf",        "font/ttf"},
            {".txt",        "text/plain"},
            {".vsd",        "application/vnd.visio"},
            {".wav",        "audio/wav"},
            {".weba",       "audio/webm"},
            {".webm",       "video/webm"},
            {".webp",       "image/webp"},
            {".woff",       "font/woff"},
            {".woff2",      "font/woff2"},
            {".xhtml",      "application/xhtml+xml"},
            {".xls",        "application/vnd.ms-excel"},
            {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {".xml",        "application/xml"},
            {".xul",        "application/vnd.mozilla.xul+xml"},
            {".zip",        "application/zip"},
            {".3gp",        "video/3gpp"},
            {".3g2",        "video/3gpp2"},
            {".7z",         "application/x-7z-compressed"}
        };
        std::unordered_map<int,std::string> _statu_msg = {
            {100,  "Continue"},
            {101,  "Switching Protocol"},
            {102,  "Processing"},
            {103,  "Early Hints"},
            {200,  "OK"},
            {201,  "Created"},
            {202,  "Accepted"},
            {203,  "Non-Authoritative Information"},
            {204,  "No Content"},
            {205,  "Reset Content"},
            {206,  "Partial Content"},
            {207,  "Multi-Status"},
            {208,  "Already Reported"},
            {226,  "IM Used"},
            {300,  "Multiple Choice"},
            {301,  "Moved Permanently"},
            {302,  "Found"},
            {303,  "See Other"},
            {304,  "Not Modified"},
            {305,  "Use Proxy"},
            {306,  "unused"},
            {307,  "Temporary Redirect"},
            {308,  "Permanent Redirect"},
            {400,  "Bad Request"},
            {401,  "Unauthorized"},
            {402,  "Payment Required"},
            {403,  "Forbidden"},
            {404,  "Not Found"},
            {405,  "Method Not Allowed"},
            {406,  "Not Acceptable"},
            {407,  "Proxy Authentication Required"},
            {408,  "Request Timeout"},
            {409,  "Conflict"},
            {410,  "Gone"},
            {411,  "Length Required"},
            {412,  "Precondition Failed"},
            {413,  "Payload Too Large"},
            {414,  "URI Too Long"},
            {415,  "Unsupported Media Type"},
            {416,  "Range Not Satisfiable"},
            {417,  "Expectation Failed"},
            {418,  "I'm a teapot"},
            {421,  "Misdirected Request"},
            {422,  "Unprocessable Entity"},
            {423,  "Locked"},
            {424,  "Failed Dependency"},
            {425,  "Too Early"},
            {426,  "Upgrade Required"},
            {428,  "Precondition Required"},
            {429,  "Too Many Requests"},
            {431,  "Request Header Fields Too Large"},
            {451,  "Unavailable For Legal Reasons"},
            {501,  "Not Implemented"},
            {502,  "Bad Gateway"},
            {503,  "Service Unavailable"},
            {504,  "Gateway Timeout"},
            {505,  "HTTP Version Not Supported"},
            {506,  "Variant Also Negotiates"},
            {507,  "Insufficient Storage"},
            {508,  "Loop Detected"},
            {510,  "Not Extended"},
            {511,  "Network Authentication Required"}
        };
class Util
{
public:
    //字符串分隔
    static size_t Split(const std::string& src,const std::string& sep,std::vector<std::string>& result)
    {
        int offset = 0;
        while(offset<src.size())
        {
            int pos = src.find(sep,offset);
            if(pos==std::string::npos)
            {
                result.push_back(src.substr(offset));
                return result.size();
            }
            if(pos==offset)
            {
                offset = pos + sep.size();
                continue;
            }
            result.push_back(src.substr(offset,pos-offset));
            offset = pos + sep.size();
        }
        return result.size();
    }
    //读取文件的所有内容，将读取的内容放到一个Buffer中
    static bool ReadFile(const std::string& filename,std::string* buff)
    {
        std::ifstream ifs(filename,std::ios::binary);
        if(ifs.is_open()==false)
        {
            DLOG("打开文件失败");
            return false;
        }
        //先获取文件的总大小
        int fsize = 0;
        ifs.seekg(0,ifs.end);
        fsize = ifs.tellg();
        ifs.seekg(0,ifs.beg);
        buff->resize(fsize);
        ifs.read(&(*buff)[0],fsize);
        if(ifs.good()==false)
        {
            DLOG("读取文件内容失败");
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
    //向文件写入数据
    static bool WriteFile(const std::string& filename,const std::string& buff)
    {
        std::ofstream ofs(filename,std::ios::binary|std::ios::trunc);
        if(ofs.is_open()==false)
        {
            DLOG("打开文件失败");
            return false;
        }
        ofs.write(&buff[0],buff.size());
        if(ofs.good()==false)
        {
            DLOG("写入数据失败");
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }
    //URL编码，避免URL中资源路径与查询字符串中的特殊字符与HTTP请求中特殊字符产生歧义
    //编码格式：将特殊字符的ascii值，转换为两个16进制字符，前缀%   C++ -> C%2B%2B
    //  不编码的特殊字符： RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
    //RFC3986文档规定，编码格式 %HH 
    //W3C标准中规定，查询字符串中的空格，需要编码为+， 解码则是+转空格
    static std::string UrlEncode(const std::string url,bool convert_space_to_plus)
    {
        std::string ret;
        for(auto &e:url)
        {
            if(e=='.'||e=='-'||e=='_'||e=='~'||isalnum(e))
            {
                ret+=e;
                continue;
            }
            if(e==' '&&convert_space_to_plus)
            {
                ret+="+";
                continue;
            }
            //剩下的都需要进行编码
            char buf[4]={0};
            snprintf(buf,4,"%%%02X",e);
            ret+=buf;
        }
        return ret;
    }
    static int HEXTOI(char c)
    {
        if(c>='0'&&c<='9')
        {
            return c-'0';
        }
        else if(c>='a'&&c<='z')
        {
            return c-'a'+10;
        }
        else if(c>='A'&&c<='Z')
        {
            return c-'A'+10;
        }
        return -1;
    }
    //Url解码
    static std::string UrlDecode(const std::string url,bool convert_space_to_plus)
    {
        std::string ret;
        for(int i = 0;i<url.size();i++)
        {
            if(url[i]=='+'&&convert_space_to_plus)
            {
                ret+=" ";
                continue;
            }
            if(url[i]=='%'&&i+2<url.size())
            {
                int v1 = HEXTOI(url[i+1]);
                int v2 = HEXTOI(url[i+2]);
                char v = (v1<<4)+v2;
                ret+=v;
                i+=2;
                continue;
            }
            ret+=url[i];
        }
        return ret;
    }
    //响应状态码的描述信息获取
    static std::string StatuDesc(int code)
    {
        auto it = _statu_msg.find(code);
        if(it==_statu_msg.end())
        {
            return "UnKnow";
        }
        return it->second;
    }
    //根据文件后缀名获取文件mime
    static std::string ExtMime(const std::string filename)
    {
        auto pos = filename.find_last_of(".");
        if(pos==std::string::npos)
        {
            return "application/octet-stream";
        }
        std::string ret = filename.substr(pos);
        auto it = mimes.find(ret);
        if(it==mimes.end())
        {
            return "application/octet-stream";
        }
        return it->second;
    }
    //判断一个文件是否是一个目录
    static bool IsDirectory(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret<0)
        {
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    //判断一个文件是否是一个普通文件
    static bool IsRegular(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret<0)
        {
            return false;
        }
        return S_ISREG(st.st_mode);
    }
    //http请求的资源路径有效性判断
    static bool ValidPath(const std::string pathname)
    {
        int level = 0;
        std::vector<std::string> src;
        Split(pathname,"/",src);
        for(auto &e:src)
        {
            if(e=="..")
            {
                level--;
                if(level<0)
                {
                    return false;
                }
                continue;
            }
            level++;
        }
        return true;
    }
};

//http请求
class HttpRequest
{
public:
    HttpRequest():_version("HTTP/1.1"){}
    void ReSet()
    {
        _method.clear();
        _path.clear();
        _version="HTTP/1.1";
        _body.clear();
        _headers.clear();
        _params.clear();
        std::smatch smh;
        _matches.swap(smh);
    }
    //设置头部字段
    void SetHeader(const std::string& key,const std::string& value)
    {
        // auto it = _headers.find(key);
        // if(it != _headers.end())
        // {
        //     DLOG("该字段已经存在插入头部字段失败");
        //     return ;
        // }
        _headers.insert(std::make_pair(key,value));
    }
    //获取指定头部字段的值
    std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
        {
            DLOG("不存在该字段");
            return "";
        }
        return it->second;
    }
    //判断头部字段是否存在
    bool HasHeader(const std::string key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
        {
            //DLOG("不存在该字段");
            return false;
        }
        return true;
    }
    //设置查询字符串
    void SetParams(const std::string& key,const std::string& value)
    {
        // auto it = _params.find(key);
        // if(it != _params.end())
        // {
        //     DLOG("该字段已经存在插入头部字段失败");
        //     return ;
        // }
        _params.insert(std::make_pair(key,value));
    }
    //获取指定查询字符串的值
    std::string GetParams(const std::string& key) 
    {
        auto it = _params.find(key);
        if(it == _params.end())
        {
            DLOG("不存在该字段");
            return "";
        }
        return it->second;
    }
    //判断查询字符串是否存在
    bool HasParams(const std::string& key)
    {
        auto it = _params.find(key);
        if(it == _params.end())
        {
            DLOG("不存在该字段");
            return false;
        }
        return true;
    }
    //获取正文长度
    size_t GetBodySize() 
    {
        bool ret = HasHeader("Content-Length");
        if(ret==false)
        {
            //DLOG("未找到该字段");
            return 0;
        }
        std::string len = GetHeader("Content-Length");
        return std::stol(len);
    }
    //判断是否为长连接
    bool Close() const
    {
        if(HasHeader("Connection")==true&&GetHeader("Connection")=="keep-alive")
        {
            return false; 
        }
        return true;
    }
public:
    std::string _method;//请求方法
    std::string _path;//资源路径
    std::string _version;//http版本
    std::string _body;//正文
    std::unordered_map<std::string,std::string> _headers;//头部字段
    std::unordered_map<std::string,std::string> _params;//查询字符串
    std::smatch _matches;//资源路径分隔
};

class HttpResponse
{
public:
    HttpResponse():_statu_code(200),_is_redirect(false) {}
    HttpResponse(const int code):_statu_code(code),_is_redirect(false) {}
    void ReSet()
    {
        _statu_code=200;
        _is_redirect=false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }
    //设置头部字段
    void SetHeader(const std::string& key,const std::string& value)
    {
        // auto it = _headers.find(key);
        // if(it != _headers.end())
        // {
        //     DLOG("该字段已经存在插入头部字段失败");
        //     return ;
        // }
        _headers.insert(std::make_pair(key,value));

    }
    //获取指定头部字段的值
    std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
        {
            DLOG("不存在该字段");
            return "";
        }
        return it->second;
    }
    //判断头部字段是否存在
    bool HasHeader(const std::string key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
        {
            //DLOG("不存在该字段");
            return false;
        }
        return true;
    }
    //设置正文
    void SetContent(const std::string& body,const std::string& type="text/html")
    {
        _body = body;
        SetHeader("Content-Type",type);
    }
    //设置重定向
    void SetRedirect(const std::string& url,const int code = 302)
    {
        _statu_code=code;
        _is_redirect=true;
        _redirect_url=url;
    }
    //判断是否为短连接
    bool Close()
    {
        if(HasHeader("Contection")==true&&GetHeader("Contection")=="keep-alive")
        {
            return false; 
        }
        return true;
    }
public:
    int _statu_code;//状态码
    std::string _body;//正文
    bool _is_redirect;//是否重定向
    std::string _redirect_url;//重定向的目标资源路径
    std::unordered_map<std::string,std::string> _headers;
};



//接收并解析请求状态
typedef enum
{
    RECV_HTTP_ERROR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
} HttpRecvStatu;
//上下文处理

#define MAX_LINE_SIZE 8192
class HttpContent
{
public:
    HttpContent():_resp_statu_code(200),_recv_statu(RECV_HTTP_LINE) {}
    //获取状态码
    int HttpStatuCode() { return _resp_statu_code; }
    //获取接收状态
    HttpRecvStatu RecvStatu() { return _recv_statu; }
    //获取请求
    HttpRequest& GetRequest() { return _request; }
    void ReSet()
    {
        _recv_statu = RECV_HTTP_LINE;
        _resp_statu_code = 200;
        _request.ReSet();
    }
    //接收并解析请求
    void RecvHttpRequest(Buffer* buff)
    {
        //？？？是否需要循环进行读取缓冲区数据直到解析出一条完整请求报文
        switch(_recv_statu)
        {
            case RECV_HTTP_LINE: RecvHttpLine(buff);
            case RECV_HTTP_HEAD: RecvHttpHeader(buff);
            case RECV_HTTP_BODY: RecvHttpBody(buff);
        }
        return;
    }
private:
    //解析请求行
    bool ParseHttpLine(std::string& line)
    {
        /*
        0:GET /baidu/login?name=cqy&password=123321 HTTP=1.1
        1:GET
        2:/baidu/login
        3:name=cqy&password=123321
        4:HTTP=1.1
        */
        std::smatch smh;
        std::regex e("(GET|POST|HEAD|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1.[01])(?:\n|\r\n)?",std::regex::icase);
        //  ?:表示进行捕捉  ?:[\n|\r\n]?   ?表示0次或1次
        std::regex_match(line,smh,e);
        _request._method = smh[1];
        std::transform(_request._method.begin(),_request._method.end(),_request._method.begin(),::toupper);
        _request._path = Util::UrlDecode(smh[2],false);
        _request._version = smh[4];
        std::string query_str = smh[3];
        std::vector<std::string> query_str_arry;
        Util::Split(query_str,"&",query_str_arry);
        for(auto& qstr:query_str_arry)
        {
            //name=cqy  
            auto pos = qstr.find("=");
            if(pos==std::string::npos)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu_code = 400;//URI Too Long
                return false;
            }
            std::string key = Util::UrlDecode(qstr.substr(0,pos),true);
            std::string value = Util::UrlDecode(qstr.substr(pos+1),true);
            _request.SetParams(key,value);
        }
        return true;
    }
    //接收请求行
    bool RecvHttpLine(Buffer* buff)
    {
        std::string line = buff->GetLine();
        if(line.size()==0)
        {
            if(buff->ReadAbleSize()>MAX_LINE_SIZE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu_code = 414;//URI Too Long
                return false;
            }
            //只是缓冲区没有数据
            return false;//继续等待数据
        }
        if(line.size()>MAX_LINE_SIZE)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu_code = 414;//URI Too Long
            return false;
        }
        //数据读取成功
        bool ret = ParseHttpLine(line);
        if(ret==false)
        {
            return false;
        }
        buff->MoveReadOffset(line.size());
        _recv_statu = RECV_HTTP_HEAD;
        return true;
    }
    //解析头部字段
    bool ParseHttpHeader(std::string& line)
    {
        if (line.back() == '\n') line.pop_back();//末尾是换行则去掉换行字符
        if (line.back() == '\r') line.pop_back();//末尾是回车则去掉回车字符
        int pos = line.find(": ");
        if(pos==std::string::npos)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu_code = 400;//
            return false;
        }
        std::string key = line.substr(0,pos);
        std::string value = line.substr(pos+2);
        _request.SetHeader(key,value);
        return true;
    }
    //接收头部字段
    bool RecvHttpHeader(Buffer* buff)
    {
        if(_recv_statu!=RECV_HTTP_HEAD)
        return false;
        while(true)
        {
            std::string line = buff->GetLineAndPop();
            if(line.size()==0)
            {
                if(buff->ReadAbleSize()>MAX_LINE_SIZE)
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu_code = 414;//URI Too Long
                    return false;
                }
                //只是缓冲区没有数据
                return true;//继续等待数据
            }
            if(line.size()>MAX_LINE_SIZE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu_code = 414;//URI Too Long
                return false;
            }
            if(line=="\n"||line=="\r\n")
            {
                break;
            }
            bool ret = ParseHttpHeader(line);
            if(ret ==false)
            {
                return false;
            }
        }
        _recv_statu = RECV_HTTP_BODY;
        return true;
    }
    //接收正文
    bool RecvHttpBody(Buffer* buff)
    {
        if(_recv_statu!=RECV_HTTP_BODY)
        return false;
        //1.先获取正文长度
        size_t content_len = _request.GetBodySize();
        if(content_len==0)
        {
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        //2.获取当前已经接收了多少正文
        size_t recv_len = content_len - _request._body.size();
        if(buff->ReadAbleSize()>=recv_len)
        {
            //说明获取了报文的一部分数据
            _request._body.append(buff->ReadPosition(),recv_len);
            buff->MoveReadOffset(recv_len);
            _recv_statu = RECV_HTTP_OVER;
            //DLOG("解析成功");
            return true;
        }
        //不足以一条报文数据，先将数据提取出来，继续等待数据
        _request._body.append(buff->ReadPosition(),buff->ReadAbleSize());
        buff->MoveReadOffset(buff->ReadAbleSize());
        return true;
    }
private:
    int _resp_statu_code;//状态码
    HttpRecvStatu _recv_statu;//接收请求的状态
    HttpRequest _request;//已经解析得到的请求信息
};

#define DEFAULT_TIMEOUT 10
//HttpServer
class HttpServer
{
public:
    using Handler = std::function<void(const HttpRequest &,HttpResponse *)>;
    using Handlers = std::vector<std::pair<std::regex,Handler>>;
    HttpServer(int port,int timeout = DEFAULT_TIMEOUT):_server(port)
    {
        EnableInactiveRelease(timeout);
        _server.SetConnectCallBack(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
        _server.SetMessageCallBack(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2));
    }
    void SetBaseDir(const std::string &basedir) 
    {
        assert(Util::IsDirectory(basedir)); 
        _basedir = basedir;
    }
    void Get(const std::string& pattern,const Handler& handler)
    {
        _get_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Post(const std::string& pattern,const Handler& handler)
    {
        _post_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Put(const std::string& pattern,const Handler& handler)
    {
        _put_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Delete(const std::string& pattern,const Handler& handler)
    {
        _delete_route.push_back(std::make_pair(std::regex(pattern),handler));
    }

    //设置线程数
    void SetThreadCount(int num)
    {
        _server.SetThreadLoopCount(num);
    }
    //启动服务器
    void Start()
    {
        _server.Start();
    }
private:
    //设置非活跃销毁
    void EnableInactiveRelease(int timeout)
    {
        _server.EnableInactiveRelease(timeout);
    }
    void ErrorHandler(HttpResponse* resp)
    {
        //1. 组织一个错误展示页面
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(resp->_statu_code);
        body += " ";
        body += Util::StatuDesc(resp->_statu_code);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        //2. 将页面数据，当作响应正文，放入rsp中
        resp->SetContent(body, "text/html");
    }
    //将请求按照http协议格式进行发送
    void WriteResponse(const ConnectionPtr& conn,const HttpRequest& req,HttpResponse& resp)
    {
        //1.先设置头部字段
        if(req.Close()==true)//如果为短连接
        {
            resp.SetHeader("Connection","close");
        }
        else
        {
            resp.SetHeader("Connection","keep-alive");
        }
        //存在正文并且未设置头部信息
        if(!resp._body.empty()&&resp.HasHeader("Content-Length")==false)
        {
            resp.SetHeader("Content-Length",std::to_string(resp._body.size()));
        }
        //存在正文且未设置正文属性
        if(!resp._body.empty()&&resp.HasHeader("Content-Type")==false)
        {
            resp.SetHeader("Content-Type","application/octet-stream");
        }
        if(resp._is_redirect==true)
        {
            resp.SetHeader("Location",resp._redirect_url);
        }
        //2.组织http响应字符串
        std::stringstream resp_str;
        resp_str<< req._version<<" "<<std::to_string(resp._statu_code)<<" "<<Util::StatuDesc(resp._statu_code)<<"\r\n";
        for(auto& head:resp._headers)
        {
            resp_str<<head.first<<": "<<head.second<<"\r\n";
        }
        resp_str<<"\r\n";
        resp_str<<resp._body;
        //3.发送数据
        conn->Send(resp_str.str().c_str(),resp_str.str().size());
    }
    bool IsFileHandler(const HttpRequest& req)
    {
        //1.是否存在根目录
        if(_basedir.empty())
        {
            return false;
        }
        //2.判断是否为"GET","HEAD"请求方法
        if(req._method!="GET"&&req._method!="HEAD")
        {
            return false;
        }
        //3.判断路径是否有效
        if(Util::ValidPath(req._path)==false)
        {
            return false;
        }
        std::string req_path = _basedir + req._path;
        //4.判断是否为目录文件
        if(req_path.back()=='/')
        {
            req_path += "index.html";
        }
        //？？？？？？检查是否是可支持的静态资源扩展名

        //判断是否为普通文件
        if(Util::IsRegular(req_path)==false)
        {
            return false;
        }
        return true;
    }
    //静态资源的处理
    void FileHandler(const HttpRequest& req,HttpResponse* resp)
    {
        std::string req_path = _basedir + req._path;
        if(req._path.back()=='/')
        {
            req_path += "index.html";
        }
        //1.获取该路径下的内容填充到resp._body中
        bool ret = Util::ReadFile(req_path,&resp->_body);
        if(ret == false)
        {
            resp->_statu_code = 404; // 文件未找到
            return ;
        }
        std::string mime = Util::ExtMime(req_path);
        resp->SetHeader("Content-Type",mime);
        return ;
    }
    //功能性请求的分类处理
    void Dispatcher(HttpRequest& req,HttpResponse* resp,Handlers& handlers)
    {
        for(auto& handler:handlers)
        {
            const std::regex& rg = handler.first;
            const Handler& functor = handler.second;
            bool ret = std::regex_match(req._path,req._matches,rg);
            if(ret == false)
            {
                continue;
            }
            return functor(req,resp);
        }
        resp->_statu_code = 404; 
    }
    //请求方法匹配
    void Route(HttpRequest& req,HttpResponse* resp)
    {
        //1.判断是否为静态资源请求
        if(IsFileHandler(req)==true)
        {
            return FileHandler(req,resp);
        }
        //2.为动态请求，需判断是哪种请求
        if(req._method=="GET"||req._method=="HEAD")
        {
            return Dispatcher(req,resp,_get_route);
        }
        else if(req._method=="POST")
        {
            return Dispatcher(req,resp,_post_route);
        }
        else if(req._method=="PUT")
        {
            return Dispatcher(req,resp,_put_route);
        }
        else if(req._method=="DELETE")
        {
            return Dispatcher(req,resp,_delete_route);
        }
        resp->_statu_code = 405;// Method Not Allowed
    }
    //设置上下文
    void OnConnected(const ConnectionPtr& conn)
    {
        conn->SetContext(HttpContent());
        // conn->SetCloseCallBack([this](const ConnectionPtr& conn) {
        // DLOG("Connection closed: %p", conn.get());
    //});
        DLOG("获取到新连接 %p",conn.get());
    }
    //结束请求消息并进行解析构建应答回复
    void OnMessage(const ConnectionPtr& conn,Buffer* buff)
    {
        // DLOG("进入消息处理");
        // DLOG("%ld",buff->ReadAbleSize());
        while(buff->ReadAbleSize()>0)
        {
            //1.获取上下文
            HttpContent *context = conn->GetContext()->Get<HttpContent>();
            //2.通过上下文将缓冲区数据进行解析（如果上下文的数据还不能构成一条请求，上下文+缓冲区）
            context->RecvHttpRequest(buff);
            HttpRequest &req = context->GetRequest();
            HttpResponse resp(context->HttpStatuCode());
            if(context->HttpStatuCode()>=400)
            {
                //返回一个错误页面
                ErrorHandler(&resp);
                WriteResponse(conn,req,resp);
                context->ReSet();//当出错了需要将上下文重置，不然状态一直都会是错误状态，就不会处理缓冲区的数据，导致一直循环
                buff->MoveReadOffset(buff->ReadAbleSize());//出错了就把缓冲区数据清空
                //关闭连接
                conn->ShutDown();
                return ;  
            }
            //DLOG("------------");
            //可能会解析失败
            if(context->RecvStatu() != RECV_HTTP_OVER)
            {
                //DLOG("解析失败");
                //继续等待新数据
                return;
            }
            // std::cout << "Request path: " << req._path << std::endl;
            // std::cout << "Response status: " << resp._statu_code << std::endl;
            //3.根据请求中的请求方法找到对应的处理回调，构建不同的请求
            Route(req,&resp);
            //4.构建响应并发生
            WriteResponse(conn,req,resp);
            //重置上下文
            context->ReSet();
            //5.判断是长连接还是短连接
            if(resp.Close()==true)
            conn->ShutDown();
            else
            context->ReSet(); // 重置上下文准备处理下一个请求
        }
    }
private:
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;

    std::string _basedir;//资源根目录
    TcpServer _server;
};